#pragma once

namespace redisStruct
{
	template<class T,class CopyOfT,class FreeOfT>
	struct _list_node
	{
		T _val;
		_list_node* _prev = nullptr;
		_list_node* _next = nullptr;
		_list_node()
		{};
		_list_node(const T& val) :_val(val)
		{};
		~_list_node()
		{
			
		}
	};

	template<class T1, class CopyOfT1, class FreeOfT1>
	class list;

	template<class T,class CopyOfT,class FreeOfT,class Ptr,class Ref>
	class _list_iterator
	{
		template<class T1, class CopyOfT1, class FreeOfT1>
		friend class list;
		typedef _list_node<T, CopyOfT, FreeOfT> node;
		typedef _list_iterator self;
	private:
		node* _cur;
	public:
		_list_iterator(node* node=nullptr) :_cur(node) {};

		self& operator++()
		{
			_cur = _cur->_next;
			return *this;
		}
		self operator++(int)
		{
			_list_iterator temp(*this);
			_cur = _cur->_next;
			return temp;
		}
		self& operator--()
		{
			_cur = _cur->_prev;
			return *this;
		}
		self operator--(int)
		{
			_list_iterator temp(*this);
			_cur = _cur->_prev;
			return temp;
		}

		Ptr operator->()
		{
			return &_cur->_val;
		}
		Ref operator*()
		{
			return _cur->_val;
		}

		bool operator==(const self& other)
		{
			return _cur == other._cur;
		}
		bool operator!=(const self& other)
		{
			return !(*this == other);
		}

	};

	template<class T,class CopyOfT,class FreeOfT>
	class list
	{
		typedef _list_node<T,CopyOfT,FreeOfT> node;
	public:
		typedef _list_iterator< T, CopyOfT, FreeOfT, T*, T&> iterator;
		typedef _list_iterator< T, CopyOfT, FreeOfT,const T*,const T&> const_iterator;
	private:
		node* _head;
		size_t _size = 0;
	public:
		list()
		{
			_head = new node();
			_head->_next = _head;
			_head->_prev = _head;
		}
		list(const list& other)
		{
			for (auto& e : other)
			{
				push_back(CopyOfT()(e));
			}
		}
		list& operator=(const list& other)
		{
			while (!empty())
				pop_back();
			for (auto& e : other)
			{
				push_back(CopyOfT()(e));
			}
		}
		~list()
		{
			while (!empty())
				pop_back();
			free(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		iterator begin()
		{
			return iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
		iterator end() 
		{
			return iterator(_head);
		}
		iterator push_back(const T& val)
		{
			_size++;
			node* newNode = new node(CopyOfT()(val));
			_head->_prev->_next = newNode;
			newNode->_prev = _head->_prev;
			newNode->_next = _head;
			_head->_prev = newNode;

			return iterator(newNode);
		}
		iterator pop_back()
		{
			if (_size-- <= 0)
				assert(false);
			node* popNode = _head->_prev;
			node* prevNode = popNode->_prev;
			node* nextNode = popNode->_next;
			prevNode->_next = popNode->_next;
			nextNode->_prev = popNode->_prev;
			FreeOfT()(popNode->_val);
			delete popNode;
			return iterator(_head->_next);
		}

		iterator push_front(const T& val)
		{
			_size++;
			node* newNode = new node(CopyOfT()(val));
			newNode->_next = _head->_next;
			newNode->_prev = _head;
			_head->_next->_prev = newNode;
			_head->_next = newNode;
			return iterator(newNode);
		}
		iterator pop_front()
		{
			if (_size-- <= 0)
				assert(false);
			node* popNode = _head->_next;
			node* prevNode = popNode->_prev;
			node* nextNode = popNode->_next;
			prevNode->_next = popNode->_next;
			nextNode->_prev = popNode->_prev;
			FreeOfT()(popNode->_val);
			delete popNode;
			return iterator(_head->_next);
		}
		
		bool empty() const
		{
			return _head->_next == _head && _head->_prev == _head;
		}
		size_t size() const
		{
			return _size;
		}
		void erase(iterator iter)
		{
			assert(iter != end());

			node* prev = iter._cur->_prev;
			node* next = iter._cur->_next;
			prev->_next = next;
			next->_prev = prev;
			FreeOfT()(iter._cur->_val);
			delete iter._cur;
		}
		static void test()
		{
		}
	};


}
